package com.myway.utils.ftp;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import com.myway.utils.PropertiesUtil;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import com.myway.utils.ftp.exception.FTPClientException;

/**
 * @ClassName: FTPClientUtil <br/>
 * @Description:  FTP工具类,使用者必须考虑异常情况<br/>
 * @CreateDate: 2016年5月31日 下午1:57:09 <br/>
 * @author Toby
 * @version V1.0
 */
public class FTPClientUtil {
	private static ThreadLocal<FTPClient> ftpClientThreadLocal;
	// 地址
	private static String host ;
	// 端口号
	private static int port ;
	// 账户
	private static String username ;
	// 密码
	private static String password ;
	// 二进制传送文件
	private static boolean binaryTransfer ;
	// 非交互式 每次数据连接之前，ftp client告诉ftp server开通一个端口来传输数据
	private static boolean passiveMode ;
	// 编码
	private static String encoding ;
	// 设置连接超时时间
	private static int clientTimeout;
	// 查询远程目录所有的file name
	private static List<String> listFileNames;
	// private static String filePathOfFtpserver;
	static {
		ftpClientThreadLocal = new ThreadLocal<FTPClient>();
		Properties properties = PropertiesUtil.configProperties;
		host = PropertiesUtil.getProStr(properties,"ftp.host");
		username = PropertiesUtil.getProStr(properties,"ftp.username");
		password = PropertiesUtil.getProStr(properties,"ftp.password");
		binaryTransfer = PropertiesUtil.getProBoolean(properties,"ftp.binary.transfer");
		passiveMode = PropertiesUtil.getProBoolean(properties,"ftp.passive.mode");
		encoding = PropertiesUtil.getProStr(properties,"ftp.encoding");
		port = PropertiesUtil.getProInteger(properties,"ftp.port");
		listFileNames = new ArrayList<String>();
	}
	
   /**
    * @description 获取FTP客户端连接
    * @return
    * @throws FTPClientException
    * @throws SocketException
    * @throws IOException
    */
	private static FTPClient getFTPClient() throws FTPClientException,
			SocketException, IOException {
//		if (ftpClientThreadLocal.get() != null
//				&& ftpClientThreadLocal.get().isConnected()) {
//			return ftpClientThreadLocal.get();
//		} else {
			// 构造一个FtpClient实例
			FTPClient ftpClient = new FTPClient();  
			// 设置字符集
			ftpClient.setControlEncoding(encoding); 
//			ftpClient.setConnectTimeout(clientTimeout);
			ftpClient.connect(host, port);
			// 连接后检测返回码来校验连接是否成功
			int reply = ftpClient.getReplyCode();
			if (FTPReply.isPositiveCompletion(reply)) {
				// 登陆到ftp服务器
				ftpClient.login(username, password);
				// 设置文件传输类型
				setFileType(ftpClient); 
			} else {
				ftpClient.disconnect();
			}
			if (passiveMode) {
				ftpClient.enterLocalPassiveMode();
			}
			ftpClientThreadLocal.set(ftpClient);
			return ftpClient;
//		}
	}

	/**
	 * @description 设置文件传输类型
	 * @throws FTPClientException
	 * @throws IOException
	 */
	private static void setFileType(FTPClient ftpClient)
			throws FTPClientException, IOException {
		if (binaryTransfer) {
			ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
		} else {
			ftpClient.setFileType(FTPClient.ASCII_FILE_TYPE);
		}
	}

	/**
	 * @description 断开ftp连接
	 * @throws FTPClientException
	 * @throws IOException
	 */
	public static void disconnect() throws FTPClientException, IOException {
		FTPClient ftpClient = getFTPClient();
		ftpClient.logout();
		if (ftpClient.isConnected()) {
			ftpClient.disconnect();
			ftpClient = null;
			ftpClientThreadLocal.set(ftpClient);
		}
	}

	/**
	 * @description 批量删除所有目录下的对应的文件
	 * @param delFiles
	 * @return
	 * @throws FTPClientException
	 * @throws IOException
	 */
	public static boolean deleteRemoteFiles(String[] delFiles)
			throws FTPClientException, IOException {
		 List<String> list=listNames();//获取所有的文件名
		 for(String filename:delFiles){
			 for(Iterator<String> it=list.iterator();it.hasNext();){
				 String filepath=it.next();
				 if(filepath.contains(filename)){//如果该路径包含该文件名则删除
					boolean result= getFTPClient().deleteFile(filepath);
					if(!result){
						return result;
					}
				 }
			 }
		 }
		return true;
	}

	/**
	 * @description 列出远程默认目录下所有的文件
	 * @return 远程默认目录下所有文件名的列表，目录不存在或者目录下没有文件时返回0长度的数组
	 * @throws FTPClientException
	 * @throws IOException
	 */
	public static List<String> listNames() throws FTPClientException,
			IOException {
		return listNames(null);
	}

	public static List<String> listNames(String remotePath)
			throws FTPClientException, IOException {
		return listNames(remotePath, true);
	}

	/**
	 * @description列出远程目录下所有的文件
	 * @param remotePath
	 *            远程目录名
	 * @param autoClose
	 *            是否自动关闭当前连接
	 * @return 远程目录下所有文件名的列表，目录不存在或者目录下没有文件时返回0长度的数组
	 * @throws FTPClientException
	 * @throws IOException
	 */
	public static List<String> listNames(String remotePath,
			boolean containSubdirectory) throws FTPClientException, IOException {
		if (null == remotePath) {
			remotePath = "." + File.separator;
		}
		try {
			FTPFile[] files = getFTPClient().listFiles(remotePath);
			if (files.length < 3) {
				return listFileNames;
			}
			for (FTPFile file : files) {
				if (!file.getName().equals(".") && !file.getName().equals("..")) {
					if (file.isFile()) {// 文件
						listFileNames
								.add("." + File.separator + file.getName());
					} else {// 目录
						listNames2(
								remotePath + file.getName() + File.separator,
								containSubdirectory);
					}
				}
			}
		} catch (IOException e) {
			throw new FTPClientException("列出远程目录下所有的文件时出现异常", e);
		}
		return listFileNames;
	}
	
     //listNames2递归方法
	private static void listNames2(String remotePath,
			boolean containSubdirectory) throws FTPClientException {
		try {
			FTPClient client = getFTPClient();
			client.changeWorkingDirectory(remotePath);
			FTPFile[] files = client.listFiles(remotePath);
			if (files.length < 3) {
				return;
			}
			for (FTPFile file : files) {
				if (!file.equals(".") && !file.equals("..")) {
					if (file.isFile()) {
						listFileNames.add(remotePath + file.getName());
					}
					if (file.isDirectory() && (!".".equals(file.getName()))
							&& (!"..".equals(file.getName()))) {
						String path = remotePath + file.getName()
								+ File.separator;
						listNames2(path, containSubdirectory);
					}
				}
			}
		} catch (IOException e) {
			throw new FTPClientException("列出远程目录下所有的文件时出现异常", e);
		}
	}

	/**
	 * 
	 * @param remotePath
	 *            远程路径
	 * @param fileName
	 *            要上传的文件名
	 * @param localInputStream
	 *            本地InputStream流
	 * @return
	 * @throws IOException
	 * @throws FTPClientException
	 */
	public static boolean uploadToRemote(String remotePath, String fileName,
			InputStream localInputStream) throws IOException,
			FTPClientException {
		remotePath=remotePath+File.separator;
		FTPClient client = getFTPClient();
		int reply;
		reply = client.getReplyCode();
		if (!FTPReply.isPositiveCompletion(reply)) {
			client.disconnect();
		}
		client.changeWorkingDirectory("/");
		client.makeDirectory(remotePath);//在服务端建立该文件夹
		client.changeWorkingDirectory(remotePath);
		boolean result = client.storeFile(fileName, localInputStream);
		localInputStream.close();
		return result;
	}

	/**
	 * 
	 * @param remotePath
	 *            远程路径
	 * @param localPath
	 *            本地路径
	 * @return
	 * @throws IOException
	 * @throws FTPClientException
	 * @throws IOException
	 */
	public static boolean downloadToLocal(String remotePath, String localPath)
			throws IOException, FTPClientException, IOException {
		return downloadToLocal(remotePath, localPath, null);
	}

	/**
	 * 
	 * @param remotePath
	 *            远程路径
	 * @param localPath
	 *            要下载的路径
	 * @param fileNames
	 *            所有要下载的文件名字
	 * @return
	 * @throws IOException
	 * @throws FTPClientException
	 * @throws IOException
	 */
	public static boolean downloadToLocal(String remotePath, String localPath,
			String[] fileNames) throws IOException, FTPClientException,
			IOException {
		remotePath=remotePath+File.separator;
		localPath=localPath+File.separator;
		FTPClient client = getFTPClient();
		client.changeWorkingDirectory("/");
		client.changeWorkingDirectory(remotePath);
		FTPFile[] ftpList = client.listFiles(remotePath);
		boolean result = true;
		if (null == fileNames) {
			for (FTPFile f : ftpList) {
				if (f.getSize() > 0) {
					File file = new File(localPath);
					file.mkdirs();
					OutputStream out = new FileOutputStream(localPath + f.getName());
					result = client.retrieveFile(f.getName(), out); // 下载
					out.close();
					if (!result) {
						break;
					}
				}
			}
		} else {
			for (String fileName : fileNames) {
				File file = new File(localPath);
				file.mkdirs();
				OutputStream out = new FileOutputStream(localPath
						+ File.separator + fileName);
				result = client.retrieveFile(fileName, out); // 下载
				out.close();
				if (!result) {
					break;
				}
			}
		}
		return result;
	}

	/**
	 * @param client
	 * @param fileName
	 *            远程路径名
	 * @return
	 * @throws IOException
	 * @throws FTPClientException
	 */
	public static int getRemoteFileSize(String fileName) throws IOException,
			FTPClientException {
		FTPClient client = getFTPClient();
		int size = 0;
		FTPFile[] ftpList = client.listFiles();
		for (FTPFile f : ftpList) {
			if (f.getName().equalsIgnoreCase(fileName)) {
				size = (int) f.getSize();
			}
		}
		return size;
	}

	/**
	 * 
	 * @param filename
	 *            要下载的文件名 从整个服务器中查找,可能找到多个相同名字的文件,按在服务端的路径在指定本地路径下创建想对应的路径和文件
	 * @param localPath
	 *            本地路径
	 * @return
	 * @throws Exception 
	 */
	public static boolean downloadToLocal2(String filename, String localPath)
			throws Exception {
		 List<String> list=listNames();
		 OutputStream out;
		 try{
			 for(Iterator<String> it=list.iterator();it.hasNext();){
				 String filepath=it.next();
				 if(filepath.contains(filename)){
					 String remoteFilePath=filepath.substring(1, filepath.length());
					 File file=new File(localPath+remoteFilePath);
					 new File(file.getParent()).mkdirs();
					 out= new FileOutputStream(localPath+remoteFilePath);
					 getFTPClient().retrieveFile(filepath, out); // 下载
					 out.close(); 
				 }
			 }
			 return true;
		 }catch (Exception e) {
			 return false;
		}
	}
	
	/**
	 * @description 创建远程目录允许创建多级目录
	 * @param remoteDir 远程目录
	 * @return
	 * @throws SocketException
	 * @throws IOException
	 * @throws FTPClientException
	 */
	public static boolean mkdirs(String remoteDir) throws SocketException, IOException, FTPClientException{
		String[] dirs = remoteDir.split("/");
		String remotePath=".";
		for(String dir:dirs){
			if(!dir.equals(".")&&null!=dir){
				remotePath=remotePath+File.separator+dir+File.separator;
				boolean result=getFTPClient().makeDirectory(remotePath);
				if(!result){
					return result;
				}
			}
		}
		return true;
	}
	
	
	
	/**
	 * @Name: main <br/>
	 * @description: 测试 <br/>
	 * @param args
	 * @throws FTPClientException
	 * @throws IOException
	 */
	public static void main(String[] args) throws FTPClientException, IOException {
		String remotePath = "EmailFile/EmailSources/20151209/";
		String localPath = "D://FTP-应用程序发布//EmailFile//EmailSources/20151209";
		String[] fileName = {"1f53b33ce42f434e9dfedefa926fa8e0.png"};
		boolean downloadToLocal = FTPClientUtil.downloadToLocal(remotePath, localPath,fileName);
		System.out.println(downloadToLocal);
	}
	
}
